package org.vnl.platform.impl.openjpa.std;

import java.util.Collection;

import java.util.Hashtable;
import java.util.LinkedList;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

/**
 * Contain all EntityManagerFactory for use in application.
 * 
 * @author Vaughan
 *
 */
public class EntityManagerContanier {

    private static EntityManagerContanier instance;
    
    private Hashtable<String, EntityManagerFactory> factories;
    private static final ThreadLocal<Hashtable<String, EntityManager>> currentEM = new ThreadLocal<Hashtable<String,EntityManager>>();
    
    private EntityManagerContanier() {
        factories = new Hashtable<String, EntityManagerFactory>();
    }
    
    public Collection<EntityManager> getCurrentEntityManagers() {
        if (currentEM == null) {
            return new LinkedList<EntityManager>();
        }
        Hashtable<String, EntityManager> ems = currentEM.get();
        if (ems == null) {
            return new LinkedList<EntityManager>();
        }
        return currentEM.get().values();
    }
   
    /**
     * get the instance
     * @return
     */
    public static EntityManagerContanier getInstance()  {
        if (instance == null) {
            instance = new EntityManagerContanier();
        }
        return instance;
    }
    
    /**
     * add an EntityManagerFactory with the given name
     * @param persistanceUnitName
     */
    public void addEntityMangerFactory(String persistanceUnitName) {
        if (factories.get(persistanceUnitName) != null) {
            return;
        }
        EntityManagerFactory emf = Persistence.createEntityManagerFactory(persistanceUnitName);
        factories.put(persistanceUnitName, emf);
    }
    
    /**
     * get the EntityManger that is used during this thread
     * @param name
     * @return
     */
    public EntityManager getCurrentEntityManager(String name) {
        Hashtable<String, EntityManager> table = currentEM.get();
        EntityManager em = null;
        if (table == null) {
            table = new Hashtable<String, EntityManager>();
            currentEM.set(table);
            em = createEntityManager(name);
            table.put(name, em);
        } else {
            em = table.get(name);
            if (em == null) {
                em = createEntityManager(name);
                table.put(name, em);
            }
        }
        return em;
    }

    private EntityManager createEntityManager(String name) {
        EntityManagerFactory emf = factories.get(name);
        if (emf == null) {
            emf = Persistence.createEntityManagerFactory(name);
        }
        return emf.createEntityManager();
    }
    
    /**
     * close all the EntityMan of currenty thread
     */
    public void clearCurrentManagers() {
        Hashtable<String, EntityManager> table = currentEM.get();
        if (table != null) {
            for (EntityManager em : table.values()) {
                em.clear();
                em.close();
            }
            table.clear();
        }
        currentEM.set(null);
    }
    
    /**
     * close all the EntityManagerFactory on hand
     */
    public void close() {
        clearCurrentManagers();
        for (EntityManagerFactory emf : factories.values()) {
            emf.close();
        }
        factories.clear();
    }
    
}
